home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
vol_300
/
365_03
/
vmsio.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-04-04
|
20KB
|
675 lines
/*
VMSIO.C -- replacements for lseek(), read() and close() to allow
arbitrary byte seeks with non-stream-lf files.
(The original version (file routines) were written to port the
unix ``less'' program. This version helps with the elvis port.
It may be useful elsewhere to port other utilities.)
Written by John Campbell CAMPBELL@NAUVAX.bitnet. Use as you
wish, but leave me some credit for killing myself on this when
I was sick one weekend, ok?
Also, added vms_rename as a weak replacment for link(). 4/2/91
...and because there was a routine named delete, created a vms_delete.
Sigh, Steve wanted pipe stuff, so vms_rpipe(), vms_pread() and
vms_pclose() was born. 8/2/91
Moved the tty i/o routines into this module as well. vms_open_tty()
and vms_ttyread() (ttread) 8/2/91
*/
/*
Entry points:
FILE I/O
vms_close (fd)
long vms_lseek (fd, offset, direction)
int vms_read (fd, buf, len)
int vms_rename (from, to)
vms_delete (file)
PIPE I/O
int vms_rpipe (cmd, fd, input_file)
int vms_pread (pfile, buffer, size)
int vms_rpclose(pfile)
TERMINAL I/O
vms_open_tty()
vms_ttyread(buf, len, time)
*/
static char *version = "VMSIO, version 1.0";
#include <stdio.h>
#include <errno.h>
#include <perror.h>
#define BUFSIZE 4096
/* Data and buffers used to implement vms_lseek() and vms_read() */
static struct {
int type, cur_loc, size, lastbin, maxbin, offset, eob;
} fdints[_NFILE] =
{{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},
{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1},{0,0,0,0,0,0,-1}};
static char **fdbufs[_NFILE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
typedef struct {
int loc, bstart, bend;
} seeks;
static seeks *fdseeks[_NFILE] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/* Intended use for fdseeks: fdseeks[fd][i] for i'th triple */
#define G_cur_loc fdints[fd].cur_loc
#define G_size fdints[fd].size
#define G_eof_seen fdints[fd].eof_seen
#define G_offset fdints[fd].offset
#define G_eob fdints[fd].eob
vms_close (fd)
int fd;
{
if (fd >= 0) {
/* Reset fdints[fd] and free any buffers we were using. */
fdints[fd].type = 0;
fdints[fd].cur_loc = 0;
fdints[fd].size = 0;
fdints[fd].lastbin = 0;
fdints[fd].maxbin = 0;
fdints[fd].offset = 0;
fdints[fd].eob = -1;
if (fdseeks[fd])
fdseeks[fd] = free (fdseeks[fd]);
if (fdbufs[fd])
fdbufs[fd] = free (fdbufs[fd]);
}
return (close(fd));
}
long vms_lseek (fd, offset, direction)
int fd, offset, direction;
{
int tmp;
if (fd > _NFILE) {
fprintf (stderr,"Too many files for vms_lseek\n");
exit(1);
}
if (fd < 0) {
return lseek (fd, offset, direction);
}
if (fdints[fd].type == 0)
_init(fd);
if (fdints[fd].type == 1)
return lseek (fd, offset, direction);
/* Convert the possibly relative `offset' to an absolute offset. */
if (direction == 1) {
offset = G_cur_loc + offset + G_offset;
}
else if (direction == 2) {
if (G_eob == -1)
_refill (fd, -1); /* Figure out the correct eob byte count */
offset = G_eob + offset;
}
if (offset < 0)
return -1;
/* Limitation of this implementation--only seeks to end of file. */
if (G_eob > -1 && offset > G_eob)
offset = G_eob;
if (G_offset > offset || offset >= G_offset + G_size) {
if (_refill (fd, offset) == -1)
return -1;
}
/* Byte we want is now in our current buffer. */
G_cur_loc = offset - G_offset;
/* Sanity check. */
if (G_cur_loc < 0 || G_cur_loc > BUFSIZE)
_error ("G_cur_loc error in vms_lseek\n", 1);
return G_cur_loc + G_offset; /* Byte location in current buffer */
}
int vms_read (fd, buf, len)
int fd, len;
char *buf;
{
/* Buffer the read as the unix system would do. */
int fill = 0, n, num = 0,tmp;
char *buffer;
if (fd > _NFILE) {
fprintf (stderr,"Too many files for vms_read\n");
exit(1);
}
if (fdints[fd].type == 0)
_init(fd);
if (fdints[fd].type == 1)
return read (fd, buf, len);
buffer = fdbufs[fd];
if (G_eob != -1 && G_cur_loc + G_offset >= G_eob)
return 0; /* EOF */
/* Move any buffered data into place. */
while (len && G_cur_loc < G_size) {
*buf++ = buffer[G_cur_loc++];
--len;
++num;
}
/* Refill as many buffers as necessary to put len bytes into buf. */
do {
/* Don't refill when asked to read beyond the end of the file. */
if (G_cur_loc == G_size && (G_eob == -1 || G_offset + G_size < G_eob)) {
if (_refill (fd, G_offset + G_size) == -1) return -1;
}
while (len && G_cur_loc < G_size) {
*buf++ = buffer[G_cur_loc++];
--len;
++num;
}
} while (len && (G_eob == -1 || G_offset + G_size < G_eob));
/* Sanity check. */
if (G_cur_loc < 0 || G_cur_loc > BUFSIZE)
_error ("G_cur_loc bad in vms_read", 1);
return num;
}
/*
Fill from the appropriate buffer. Note that offset is a true byte
offset and needs to be converted to fdseeks[fd][i].loc before seeking.
This technique may, in fact, generalize to other machines.
*/
static int _refill (fd, offset)
int fd, offset;
{
int n, seekbin, tmp;
char *buffer = fdbufs[fd];
/* See if the offset is in our current buffer (eob offset is a pain). */
if (offset > 0 && G_eob > -1 && offset >= G_eob)
offset = G_eob - 1;
if (offset > 0 && G_offset <= offset && offset < G_offset + G_size)
return G_offset;
seekbin = fdints[fd].lastbin;
/* Now see if the offset is known (already been read once). */
if (offset >= 0 && offset < fdseeks[fd][seekbin].bstart) {
/* Yes! We can seek to a known point to pick up this offset. */
while (seekbin > 0) {
if (offset >= fdseeks[fd][seekbin].bstart)
break;
--seekbin;
}
}
/* Position ourselves for the read (even if we are already there?) */
/* We can avoid this lseek if G_offset == [seekbin-1].bstart */
if (lseek (fd, fdseeks[fd][seekbin].loc, 0) == -1)
_error ("bad seek in _refill");
/* Ok, fill this buffer. */
more:
G_cur_loc = 0;
G_size = 0;
G_offset = fdseeks[fd][seekbin].bstart;
/*
Don't want to be left with a partial record. Choices are to shrink
down the read size or to keep seeking so we can backup to just before
n == read size. Which seems faster? Which puts an arbitrary limit
on the record size?
*/
/* Some lines longer than 512 may be truncated. */
while (G_size < BUFSIZE - 512 &&
(n = read (fd, &buffer[G_size], BUFSIZE - G_size)) > 0) {
#ifdef OTHERMETHOD
if (n == BUFSIZE - G_size)
break; /* Don't count last line (it may be a partial line) */
#endif
G_size += n;
}
if (n == 0) {
if (G_size == 0)
++G_size;
G_eob = G_offset + G_size;
offset = G_eob;
}
else if (n == -1) {
_error ("vms_read (_refill) error", 0);
return -1;
}
/* Update the seek array. Finish current bin and start next bin. */
if (G_size == 0)
++G_size;
tmp = G_offset + G_size - 1;
if (seekbin < fdints[fd].lastbin && fdseeks[fd][seekbin].bend != tmp) {
fprintf (stderr, "Consistency failure in _refill\n");
exit(1);
}
fdseeks[fd][seekbin].bend = tmp;
if (G_eob == -1 || G_offset + G_size < G_eob) {
/* Set up the next seek bin */
if (++seekbin > fdints[fd].maxbin) {
/* Make more room. */
fdints[fd].maxbin = 2